#include "gp_qpcr_server.h"
#include <string.h>
#include <fstream>
#include <list>

#define MAX_CAPACITY_DJPUMP 480


typedef struct _OneTrace
{
   char * start;
   char * end;
   int quantity;
}OneTrace;

#define MAX_QUANTITY 480

int split_trace(char * traceIn, int lenIn, 
                int quantity_air, int quantity_spit, int & quantitySpitAll,
                std::list<OneTrace>& tracesOut)
{
    //int suckAll = quantity_air + quantity_suck;
    int maxSpit = MAX_QUANTITY - quantity_air;

    char * ptrBuff = traceIn;
    
    char * ptrTemp = ptrBuff;
    
    char buffOneHole[64];
    memset(buffOneHole,0,64);
    
    ptrBuff = strchr(ptrBuff,',');

    OneTrace oneTrace;
    oneTrace.start = traceIn;
    oneTrace.quantity = 0;
    oneTrace.end = traceIn;
    
    int quantity1Hole = 0;
    quantitySpitAll = 0;
  
    while(ptrBuff)
    {
         memcpy(buffOneHole,ptrTemp,ptrBuff-ptrTemp); 
         quantity1Hole = atoi(ptrTemp+2);
         oneTrace.quantity += quantity1Hole;
         quantitySpitAll += quantity1Hole;
         if(oneTrace.quantity > maxSpit)
         {
            oneTrace.end = ptrTemp - 1;
            oneTrace.quantity -= quantity1Hole;
            tracesOut.push_back(oneTrace);
            
            oneTrace.start = ptrTemp;
            oneTrace.quantity = quantity1Hole;
         }
         ptrTemp = ptrBuff+1;
         ptrBuff = strchr(ptrTemp,',');
         memset(buffOneHole,0,64);
    }


    if(strlen(ptrTemp))
    {
        quantity1Hole = atoi(ptrTemp+2);
        oneTrace.quantity += quantity1Hole;
        quantitySpitAll += quantity1Hole;
        if(oneTrace.quantity > maxSpit)
        {
            oneTrace.end = ptrTemp - 1;
            oneTrace.quantity -= quantity1Hole;
            tracesOut.push_back(oneTrace);
            
            oneTrace.start = ptrTemp;
            oneTrace.quantity = quantity1Hole;
        }
    }

    oneTrace.end = ptrTemp + strlen(ptrTemp);
    tracesOut.push_back(oneTrace);

    quantitySpitAll += quantity_spit;
    return 0;
}

int procDjAddSample(const DjAddSampleParam* request,Response* reply)
{
   //std::cout<<"enter in procDjAddSample"<<std::endl;
   int totalSuckQuantity = request->quantityair() 
                         + request->quantitysuck();
   
   int maxSpitQuan = MAX_CAPACITY_DJPUMP - 
                     request->quantityair() - 
                     request->quantitydrop();

   if(request->traceline().length() > 1023)
   {
       printf("trace line string is two long\n");
       reply->set_statecode(1);
       reply->set_errornum(8);
       return 8;
   }

   char strBuff[1024];
   memset(strBuff,0,1024);
   
   memcpy(strBuff,request->traceline().c_str(),request->traceline().length());

//    //std::cout<<"enter in procDjAddSample 111"<<std::endl;
//    char * ptrCurrPos = strBuff;
//    char * ptrCurrPosTmp = ptrCurrPos;
//    char * ptrMax = NULL;
//    ptrCurrPos = strchr(ptrCurrPos,',');

//    int quantitySpit = 0;
//    int quantityOneHole= 0;
//    int quantitySpitMax = 0;
//    while(ptrCurrPos)
//    {
//        quantityOneHole = atoi(ptrCurrPosTmp+2);
//        //std::cout<<"quantityOneHole:"<<quantityOneHole<<std::endl;
//        quantitySpit += quantityOneHole;
       
//        if(quantitySpit>maxSpitQuan && ptrMax == NULL)
//        {
//            ptrMax = ptrCurrPosTmp;
//            quantitySpitMax = quantitySpit - quantityOneHole;
//        }

//        ptrCurrPosTmp = ptrCurrPos + 1;
//        ptrCurrPos = strchr(ptrCurrPosTmp,',');
//    }

//    if(strlen(ptrCurrPosTmp)!=0)
//    {
//        quantityOneHole = atoi(ptrCurrPosTmp + 2);
//        quantitySpit += quantityOneHole;

//        if(quantitySpit>maxSpitQuan && ptrMax == NULL)
//        {
//            ptrMax = ptrCurrPosTmp;
//            quantitySpitMax = quantitySpit - quantityOneHole;
//        }
//    }

//    if(quantitySpit > request->quantitysuck())
//    {
//         printf("suck quanlity is not enough for spit\n");
//         return 1;
//    }
//     int quanSuckOnce = 0;
//     if(ptrMax)
//     {
//         printf("spit quantity do not exceed the capacity\n");
//         quanSuckOnce = quantitySpitMax;
//     }
//     else 
//     {
//         //totalSuckQuantity = quantitySpit;

//         if(totalSuckQuantity<MAX_CAPACITY_DJPUMP)
//         {
//             quanSuckOnce = (request->quantitysuck() < quantitySpit)?quantitySpit:request->quantitysuck();
//         }
//         else
//         {
//             quanSuckOnce = quantitySpit;
//         }
//     }
    std::list<OneTrace> tracesResult;
    int quantitySpitAll = 0;
    split_trace(strBuff, strlen(strBuff), 
                request->quantityair(), request->quantitydrop(), quantitySpitAll,
                tracesResult);
    
    int quantitySuckAll = request->quantitysuck();
    if(quantitySpitAll > quantitySuckAll)
    {
        printf("suck quantity is not enough,quantitySpitAll[%d],quantitySuckAll[%d]\n",
        quantitySpitAll,quantitySuckAll);
        reply->set_statecode(1);
        reply->set_errornum(7);
        return 7;
    }

    int traceNum = tracesResult.size();
    std::list<OneTrace>::iterator itTrace = tracesResult.begin();
    
    for(int indexTrace=0;indexTrace<traceNum;indexTrace++)
    {
        std::cout<<"to suck reagnet,quantity is:"<<itTrace->quantity<<std::endl;

        //here update the config for dj sample, the config of suck reagent quantity 
        dj_reagent djReagentParam;
        memset(&djReagentParam,0,sizeof(dj_reagent));
        
        djReagentParam.quantity_air = request->quantityair();
        djReagentParam.quantity_spit = request->quantitydrop();
        djReagentParam.quantity_suck = itTrace->quantity + request->quantitydrop();
        quantitySuckAll -= itTrace->quantity;
        //std::cout<<"air:"<<djReagentParam.quantity_air<<",spit:"
        //<<djReagentParam.quantity_spit<<",suck:"<<djReagentParam.quantity_suck<<std::endl;
        
        if(indexTrace==(traceNum-1))
        {
            quantitySuckAll -= request->quantitydrop();
           if(quantitySuckAll>0)
           {
               djReagentParam.quantity_suck += quantitySuckAll;
               int maxSuckQuantity = MAX_QUANTITY - request->quantityair();
               if(djReagentParam.quantity_suck > maxSuckQuantity)
               {
                   djReagentParam.quantity_suck = maxSuckQuantity;
               }
           }
           else if(quantitySuckAll<0)
           {
               printf("suck quantity is not enough\n");
               reply->set_statecode(1);
               reply->set_errornum(6);
               return 6;
           }
        }
        else 
        if(quantitySuckAll<0)
        {
            printf("suck quantity is not enough\n");
            reply->set_statecode(1);
            reply->set_errornum(6);
            return 6;
        }

        int ret = sendModuleMsgToAct(&djReagentParam,QUEUE_MSG_TYPE_MODULE,I_MODULE_DJREAGENT);

        if(ret)
        {
        reply->set_statecode(1);
        reply->set_errornum(ret);
        return 2;
        }
        
        msgQueueAck stMsgQueueAck;
        memset(&stMsgQueueAck,0,sizeof(msgQueueAck));
        wait_ack_module(70,&stMsgQueueAck,reply,I_MODULE_DJREAGENT);
        
        std::cout<<"suck reagent ret code:"<<reply->statecode()<<std::endl;
        if(reply->statecode() != 100)
        {
            reply->set_statecode(1);
            reply->set_errornum(3);
            return 3;
        }
        
        //write trace line to file.
        std::ofstream outfile;
        outfile.open(FILE_DJ_TRACE,std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
        if(outfile.is_open())
        {
            char buffTrace[1024];
            memset(buffTrace,0,1024);
            memcpy(buffTrace,itTrace->start,itTrace->end - itTrace->start);
            printf("trace string: %s\n",buffTrace);
            outfile.write(itTrace->start,itTrace->end - itTrace->start);
            outfile.close();
        }
        

        DjActParam djActParam;

        //memset(&djActParam,0,sizeof(DjActParam));

        

        //set dj holes param here ---------
        djActParam.set_deltax(request->deltax());
        djActParam.set_deltay(request->deltay());
        djActParam.set_initx(request->initx());
        djActParam.set_inity(request->inity());
        djActParam.set_initz(request->initz());
        djActParam.set_numsteponeact(3);
        //start add sample to 48 holes
        ret = sendDjMsgToAct(&djActParam,QUEUE_MSG_TYPE_MODULE,I_FILE_DJ);
        if(ret)
        {
            reply->set_statecode(1);
            reply->set_errornum(ret);
            return 4;
        }
        
        
        //msgQueueAck stMsgQueueAck;
        memset(&stMsgQueueAck,0,sizeof(msgQueueAck));
        wait_ack_module(120,&stMsgQueueAck,reply,I_FILE_DJ);

        std::cout<<"add to holes ret code:"<<reply->statecode()<<std::endl;
        

        itTrace++;
        // if(itTrace!=tracesResult.end())
        // {
            //start clean here
            ret = sendModuleMsgToAct(QUEUE_MSG_TYPE_MODULE,I_MODULE_DJLIQUID);
            if(ret)
            {
                reply->set_statecode(1);
                reply->set_errornum(ret);
                return 5;
            }    
        
            memset(&stMsgQueueAck,0,sizeof(msgQueueAck));
            wait_ack_module(120,&stMsgQueueAck,reply,I_MODULE_DJLIQUID);

        // }
        // else 
        // {
        //     break;
        // }      
       
    }

    reply->set_errornum(100);
    reply->set_statecode(100);

    return 0;
}